module dice.threading;

import thr = std.thread;
import std.stdio;

class ThreadMessage
{
	void handle ()
	{
		writefln("-WARNING- unhandled message %s", toString);
	}
}

class ExecMessage : ThreadMessage
{
	void delegate () dg;
	
	this (void delegate () d)
	{
		dg = d;
	}
	
	void handle ()
	{
		dg();
	}
}

class Thread : thr.Thread
{
	bool currentlyLooping = false;
	
	ThreadMessage[] messages;
	
	/** Creates a thread that calls dg upon starting */
	this (void delegate () dg)
	{
		super(cast(int delegate())dg);
	}
	
	/** Creates a thread that immediately starts and loops waiting for events */
	this ()
	{
		super(cast(int delegate())&loop);
		start();
	}
	
	/** Sends this thread/it's event loop a message */
	void send (ThreadMessage m)
	{
		synchronized (this)
		{
			messages ~= m;
			resume();
		}
	}
	
	/** Handles the specified event or message (often over-ridden) */
	private void handle (ThreadMessage m)
	{
		m.handle();
	}
	
	/** Starts the thread's event/message loop (called from the same thread) */
	void loop ()
	{
		if (!isSelf)
			throw new Exception("Some douchebag tried to run loop() on another thread! What a loser!");
		
		currentlyLooping = true;
		
		while (true)
		{
			synchronized (this)
			{
				while (messages.length > 0)
				{
					handle(messages[0]);
					messages = messages[1..messages.length];
				}
			}
			
			/** Pause the thread (it gets resumed when a message is sent) */
			pause();
		}
		
	}
}
